package com.mindata.blockchain.block.RLP;

import com.mindata.blockchain.block.Block;
import com.mindata.blockchain.block.BlockBody;
import com.mindata.blockchain.block.BlockHeader;
import com.mindata.blockchain.common.util.RLP;
import com.mindata.blockchain.common.util.RLPList;

/**
 * Created by Ming on 2018/8/10.
 */
public class BlockB {

    private static final byte[] EMPTY_BYTE_ARRAY=new byte[]{};

    private BlockHeaderB blockHeaderB;

    private BlockBodyB blockBodyB;

    private byte[] hash;

    protected byte[] rlpEncoded;

    private boolean parsed = false;

    public BlockB(){}

    public BlockB(Block block){
        this.blockHeaderB=new BlockHeaderB(block.getBlockHeader());
        this.blockBodyB=new BlockBodyB(block.getBlockBody());
        this.hash=block.getHash()!=null?block.getHash().getBytes():EMPTY_BYTE_ARRAY;
        this.rlpEncoded=null;
    }

    public BlockB(byte[] rawData){
        this.rlpEncoded=rawData;
        RLPList params=(RLPList) RLP.decode2(rlpEncoded).get(0);
        byte[] blockHeaderB = params.get(0).getRLPData();
        byte[] blockBodyB=params.get(1).getRLPData();

        if(this.blockHeaderB==null)
            this.blockHeaderB=new BlockHeaderB(blockHeaderB);

        if(this.blockBodyB==null)
            this.blockBodyB=new BlockBodyB(blockBodyB);
    }

    public synchronized void parseRLP(){
        if(parsed)
            return;
        RLPList params=(RLPList) RLP.decode2(rlpEncoded).get(0);

        this.hash=params.get(2).getRLPData();
        this.parsed=true;
    }

    public BlockHeaderB getBlockHeaderB() {
        return blockHeaderB;
    }

    public void setBlockHeaderB(BlockHeaderB blockHeaderB) {
        this.blockHeaderB = blockHeaderB;
    }

    public BlockBodyB getBlockBodyB() {
        return blockBodyB;
    }

    public void setBlockBodyB(BlockBodyB blockBodyB) {
        this.blockBodyB = blockBodyB;
        rlpEncoded=null;
    }

    public byte[] getHash() {
        parseRLP();
        return hash;
    }

    public void setHash(byte[] hash) {
        this.hash = hash;
    }

    public byte[] encode(){
        if(rlpEncoded==null){
            byte[] blockHeader=blockHeaderB.encode();
            byte[] blockBody=blockBodyB.encode();
            byte[] hash=encode(this.hash);
            this.rlpEncoded=RLP.encodeList(blockHeader,blockBody,hash);
        }
        return rlpEncoded;
    }

    public byte[] encode(byte[] var){
        return RLP.encodeElement(var);
    }

    public Block convertToBlock(){
        Block block=new Block();
        BlockHeader blockHeader = null;
        BlockBody blockBody = null;
        if(this.blockHeaderB!=null)
            blockHeader=this.blockHeaderB.convertToBlockHeader();
        if(this.blockBodyB!=null)
            blockBody=this.blockBodyB.covertToBlockBody();
        block.setBlockBody(blockBody);
        block.setBlockHeader(blockHeader);
        block.setHash(new String(getHash()));
        return block;
    }
}
